#include "studentinfowidget.h"
#include "ui_studentinfowidget.h"

#include <QDebug>
#include <QSqlDatabase>
#include <QSqlQuery>
#include <QDialog>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QGroupBox>
#include <QFormLayout>
#include <QLineEdit>
#include <QPushButton>
#include <QComboBox>
#include <QDateEdit>
#include <QLabel>
#include <QFileDialog>
#include <QStandardPaths>
#include <QMessageBox>
#include <QBuffer>
#include <QTableWidgetItem>
#include <qlist.h>
#include <QSqlError>

#include "tabledelegates.h"

StudentInfoWidget::StudentInfoWidget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::StudentInfoWidget)
{
    ui->setupUi(this);

    ui->tableWidget->verticalHeader()->setDefaultSectionSize(100);  //设置每行的默认行高
    //交替行颜色
    ui->tableWidget->setAlternatingRowColors(true);  //设置交替行颜色

    //性别列代理
    ComboBoxDelegate *genderDelegate = new ComboBoxDelegate(this);
    genderDelegate->setItems(QStringList()<<tr("man")<<tr("lady"));
    ui->tableWidget->setItemDelegateForColumn(2, genderDelegate);  //设置性别列的代理
    //设置进度列的代理
    ComboBoxDelegate *progressDelegate = new ComboBoxDelegate(this);
    progressDelegate->setItems(QStringList()<<"0%"<<"20%"<<"40%"<<"60%"<<"80%"<<"100%");
    ui->tableWidget->setItemDelegateForColumn(6, progressDelegate);  //设置进度列的代理
    //设置日期列的代理
    ui->tableWidget->setItemDelegateForColumn(3, new DateEditDelegate(this));  //设置生日列的代理
    ui->tableWidget->setItemDelegateForColumn(4, new DateEditDelegate(this));  //设置入学日期列的代理
    //设置照片列的代理
    ui->tableWidget->setItemDelegateForColumn(7, new PhotoDelegate(this));  //设置照片列的代理

    //设置表格的单元格改变事件
    connect(ui->tableWidget, &QTableWidget::itemChanged, this, &StudentInfoWidget::handleItemChanged);

    refreshTable();
}

StudentInfoWidget::~StudentInfoWidget()
{
    delete ui;
}

void StudentInfoWidget::refreshTable(void)
{
    ui->tableWidget->blockSignals(true);
    ui->tableWidget->setRowCount(0);

    QSqlQuery query("SELECT * FROM studentInfo");
    while (query.next()) {
        //获取数据库中一行的数据
        int row = ui->tableWidget->rowCount();
        ui->tableWidget->insertRow(row);
        for (int col = 0; col < ui->tableWidget->columnCount(); ++col) {
            //遍历每一行中的每一列的数据
            QTableWidgetItem *item = new QTableWidgetItem();
            item->setTextAlignment(Qt::AlignCenter);

            //处理照片
            if (col == ui->tableWidget->columnCount() - 1) {
                QByteArray photoData = query.value(col).toByteArray();
                if (!photoData.isEmpty()) {
                    QPixmap pixmap;
                    pixmap.loadFromData(photoData);
                    item->setData(Qt::DecorationRole, pixmap.scaled(100, 100, Qt::KeepAspectRatio));
                    item->setData(Qt::UserRole, photoData);
                }
            }else {
                //不是最后一列，则直接设置文本
                item->setText(query.value(col).toString());
            }
            ui->tableWidget->setItem(row, col, item);
        }
    }

    ui->tableWidget->blockSignals(false);
}

void StudentInfoWidget::on_pushButton_add_clicked(void)
{
    QDialog dlg(this);  //创建一个模态对话框，会在当前窗口的中间显示

    dlg.setWindowTitle(tr("Add student information"));
    dlg.setMinimumSize(600, 400);

    //设置对话框的布局
    QVBoxLayout *mainLayout = new QVBoxLayout(&dlg);
    QHBoxLayout *contentLayout = new QHBoxLayout();
    mainLayout->addLayout(contentLayout);

    //添加表单和照片区域
    QGroupBox *formGroup = createFormGroup();
    QGroupBox *photoGroup = createPhotoGroup();
    contentLayout->addWidget(formGroup, 1);  //后面的1表示拉伸因子，它控制控件在布局方向上的空间分配比例
    contentLayout->addWidget(photoGroup, 1); //后面的1表示拉伸因子，它控制控件在布局方向上的空间分配比例

    //添加按钮区域
    QHBoxLayout *buttonLayout = new QHBoxLayout();
    QPushButton *pushButton_confirm = new QPushButton(tr("Confirm"));
    QPushButton *pushButton_cancel = new QPushButton(tr("Cancel"));
    //配置按钮
    pushButton_confirm->setFixedWidth(150);
    pushButton_cancel->setFixedWidth(150);
    //添加按钮到布局中
    buttonLayout->addStretch();  //添加拉伸因子，表示在按钮前添加一个弹性空间
    buttonLayout->addWidget(pushButton_confirm);
    buttonLayout->addWidget(pushButton_cancel);
    buttonLayout->addStretch();  //添加拉伸因子，表示在按钮后添加一个弹性空间
    //连接按钮信号槽函数
    connect(pushButton_confirm, &QPushButton::clicked, &dlg, &QDialog::accept);
    connect(pushButton_cancel, &QPushButton::clicked, &dlg, &QDialog::reject);
    mainLayout->addLayout(buttonLayout);
    //执行对话框
    if (dlg.exec() == QDialog::Accepted){
        handleDialogAccepted(formGroup, photoGroup);
    }
}

QGroupBox * StudentInfoWidget::createFormGroup(void)
{
    QGroupBox *formGroup = new QGroupBox(tr("Student Information"));
    QFormLayout *formLayout = new QFormLayout(formGroup);

    //初始化控件
    QLineEdit *lineEdit_id = new QLineEdit();
    lineEdit_id->setObjectName("lineEdit_id");
    QLineEdit *lineEdit_name = new QLineEdit();
    lineEdit_name->setObjectName("lineEdit_name");
    QComboBox * comboBox_gender = new QComboBox();
    comboBox_gender->setObjectName("comboBox_gender");
    QDateEdit *dateEdit_birthday = new QDateEdit();
    dateEdit_birthday->setObjectName("dateEdit_birthday");
    QDateEdit *dataEdit_join = new QDateEdit();
    dataEdit_join->setObjectName("dataEdit_join");
    QLineEdit *lineEdit_goal = new QLineEdit();
    lineEdit_goal->setObjectName("lineEdit_goal");
    QComboBox *comboBox_progress = new QComboBox();
    comboBox_progress->setObjectName("comboBox_progress");

    //配置控件
    comboBox_gender->addItems({tr("man"), tr("lady")});
    comboBox_progress->addItems({"0%", "20%", "40%", "60%", "80%", "100%"});
    dateEdit_birthday->setDisplayFormat("yyyy-MM-dd");
    dataEdit_join->setDisplayFormat("yyyy-MM-dd");
    dateEdit_birthday->setCalendarPopup(true);  //设置日历弹出窗口
    dataEdit_join->setCalendarPopup(true);

    //添加控件到表单
    formLayout->addRow(tr("ID"), lineEdit_id);
    formLayout->addRow(tr("Name"), lineEdit_name);
    formLayout->addRow(tr("Gender"), comboBox_gender);
    formLayout->addRow(tr("Birthday"), dateEdit_birthday);
    formLayout->addRow(tr("Join Date"), dataEdit_join);
    formLayout->addRow(tr("Goal"), lineEdit_goal);
    formLayout->addRow(tr("Progress"), comboBox_progress);

    return formGroup;
}

QGroupBox * StudentInfoWidget::createPhotoGroup(void)
{
    QGroupBox *photoGroup = new QGroupBox(tr("Student Photo"));
    QVBoxLayout *photoLayout = new QVBoxLayout(photoGroup);
    //初始化控件
    QLabel *label_photo_preview = new QLabel();
    QPushButton *pushButton_photo_select = new QPushButton(tr("Select Photo"));
    //配置控件
    label_photo_preview->setAlignment(Qt::AlignCenter);
    label_photo_preview->setMinimumSize(250, 250);
    pushButton_photo_select->setFixedSize(150, 40);

    //添加控件到布局
    photoLayout->addWidget(label_photo_preview, 1, Qt::AlignCenter);
    photoLayout->addWidget(pushButton_photo_select, 0, Qt::AlignCenter); //中间的0表示不拉伸
    //连接信号槽函数
    connect(pushButton_photo_select, &QPushButton::clicked, [this, label_photo_preview](){
        QString fileName = QFileDialog::getOpenFileName(this, tr("Select Photo"), QStandardPaths::writableLocation(QStandardPaths::PicturesLocation), tr("Images (*.png *.jpg *.bmp)"));
        if (!fileName.isEmpty()) {
            QPixmap pixmap(fileName);
            if (pixmap.isNull()) {
                //如果加载失败，则提示错误
                QMessageBox::warning(this, tr("Error"), tr("Failed to load image."));
                return ;
            }
            //智能缩放
            pixmap = pixmap.scaled(label_photo_preview->width() - 30, label_photo_preview->height() - 30, Qt::KeepAspectRatio, Qt::SmoothTransformation);       //Qt::KeepAspectRatio表示保持宽高比缩放，Qt::SmoothTransformation表示平滑缩放
            label_photo_preview->setPixmap(pixmap);  //设置预览图
            //转换成字节数据
            QBuffer buffer(&m_photoData); //创建一个缓冲区，用于存储字节数据
            buffer.open(QIODevice::WriteOnly);
            pixmap.save(&buffer, "PNG");  //保存为PNG格式
            buffer.close();  //关闭缓冲区
        }
    });

    return photoGroup;
}

void StudentInfoWidget::handleDialogAccepted(QGroupBox *formGroup, QGroupBox *photoGroup)
{
    //获取表单数据
    QLineEdit *lineEdit_id = formGroup->findChild<QLineEdit *>("lineEdit_id");
    QLineEdit *lineEdit_name = formGroup->findChild<QLineEdit *>("lineEdit_name");
    QComboBox *comboBox_gender = formGroup->findChild<QComboBox *>("comboBox_gender");
    QDateEdit *dateEdit_birthday = formGroup->findChild<QDateEdit *>("dateEdit_birthday");
    QDateEdit *dataEdit_join = formGroup->findChild<QDateEdit *>("dataEdit_join");
    QLineEdit *lineEdit_goal = formGroup->findChild<QLineEdit *>("lineEdit_goal");
    QComboBox *comboBox_progress = formGroup->findChild<QComboBox *>("comboBox_progress");

    //数据校验
    if (lineEdit_id->text().isEmpty() || lineEdit_name->text().isEmpty()) {
        QMessageBox::warning(this, tr("Error"), tr("Please fill in all fields."));
        return ;
    }
    //检查学号唯一性
    QSqlQuery checkQuery;
    checkQuery.prepare("SELECT id FROM studentInfo WHERE id = ?");
    checkQuery.addBindValue(lineEdit_id->text());
    if (checkQuery.exec() && checkQuery.next()) {
        QMessageBox::warning(this, tr("Error"), tr("ID already exists."));
        return ;
    }
    //插入数据
    QSqlDatabase::database().transaction();  //开始事务
    QSqlQuery insertQuery;
    insertQuery.prepare("INSERT INTO studentInfo (id, name, gender, birthday, join_date, study_goal, progress, photo) VALUES (?, ?, ?, ?, ?, ?, ?, ?)");
    insertQuery.addBindValue(lineEdit_id->text());
    insertQuery.addBindValue(lineEdit_name->text());
    insertQuery.addBindValue(comboBox_gender->currentText());
    insertQuery.addBindValue(dateEdit_birthday->date().toString("yyyy-MM-dd"));
    insertQuery.addBindValue(dataEdit_join->date().toString("yyyy-MM-dd"));
    insertQuery.addBindValue(lineEdit_goal->text());
    insertQuery.addBindValue(comboBox_progress->currentText());
    insertQuery.addBindValue(m_photoData.isEmpty()?QVariant():m_photoData);  //存储照片数据

    qDebug() << "insertQuery:" << insertQuery.lastQuery();  //打印SQL语句

    if (!insertQuery.exec()) {
        QSqlDatabase::database().rollback();  //回滚事务
        QMessageBox::warning(this, tr("Error"), tr("Failed to add student information."));
        return ;
    }
    QSqlDatabase::database().commit();  //提交事务
    //刷新表格
    refreshTable();
    QMessageBox::information(this, tr("Success"), tr("Student information added successfully."));
}

void StudentInfoWidget::on_pushButton_del_item_clicked(void)
{
    //无法删除id列
    if (ui->tableWidget->currentColumn() == 0) {
        QMessageBox::warning(this, tr("Error"), tr("Cannot delete ID column."));
        return ;
    }
    //获取某项数据
    auto selected = ui->tableWidget->selectedItems();
    if (selected.isEmpty()) {
        QMessageBox::warning(this, tr("Error"), tr("Please select a row to delete."));
        return ;
    }
    //开始事务
    QSqlDatabase::database().transaction();  //开始事务
    //删除所有选中项数据
    for (const auto &item : selected) {
        int row = item->row();
        int col = item->column();
        QString id = ui->tableWidget->item(row, 0)->text();  //获取学号

        const QStringList columns = {"id", "name", "gender", "birthday", "join_date", "study_goal", "progress", "photo"};

        QSqlQuery deleteQuery;
        deleteQuery.prepare(QString("UPDATE studentInfo SET %1 = ? WHERE id = ?").arg(columns[col]));
        deleteQuery.addBindValue("");   //将数据库中对应列的数据置空，就相当于删除
        deleteQuery.addBindValue(id);
        if (!deleteQuery.exec()) {
            QSqlDatabase::database().rollback();  //回滚事务
            QMessageBox::warning(this, tr("Error"), tr("Failed to delete student information."));
            return ;
        }
    }
    QSqlDatabase::database().commit();  //提交事务
    //刷新表格
    refreshTable();
    QMessageBox::information(this, tr("Success"), tr("Student information deleted successfully."));
}

void StudentInfoWidget::on_pushButton_del_line_clicked(void)
{
    auto selected = ui->tableWidget->selectionModel()->selectedRows();
    if (selected.isEmpty()) {
        QMessageBox::warning(this, tr("Error"), tr("Please select a row to delete."));
        return ;
    }
    //事务处理
    QSqlDatabase::database().transaction();  //开始事务
    //删除选中的行
    for (const auto &index : selected) {
        int row = index.row();
        QString id = ui->tableWidget->item(row, 0)->text();  //获取学号
        QSqlQuery deleteQuery;
        deleteQuery.prepare("DELETE FROM studentInfo WHERE id = ?");
        deleteQuery.addBindValue(id);
        if (!deleteQuery.exec()) {
            QSqlDatabase::database().rollback();  //回滚事务
            QMessageBox::warning(this, tr("Error"), tr("Failed to delete student information."));
            return ;
        }
    }
    QSqlDatabase::database().commit();  //提交事务
    //刷新表格
    refreshTable();
    QMessageBox::information(this, tr("Success"), tr("Student information deleted successfully."));
}

//处理表格项改变事件
void StudentInfoWidget::handleItemChanged(QTableWidgetItem *item)
{
    //获取当前行和列
    const int row = item->row();
    const int col = item->column();

    //无法修改id
    if (col == 0) {
        QMessageBox::warning(this, tr("Error"), tr("ID cannot be modified."));
        //刷新表格
        refreshTable();
        return ;
    }
    //获取学号
    const QString id = ui->tableWidget->item(row, 0)->text();  //获取学号
    //获取数据库字段
    const QString columnName = QStringList{"id", "name", "gender", "birthday", "join_date", "study_goal", "progress", "photo"}[col];

    //开始事务
    QSqlDatabase::database().transaction();  //开始事务
    //更新数据
    try
    {
        //准备更新语句
        QSqlQuery updateQuery;
        updateQuery.prepare(QString("UPDATE studentInfo SET %1 = ? WHERE id = ?").arg(columnName));
        //绑定参数
        if (columnName == "photo") {  //如果是照片列
            updateQuery.addBindValue(item->data(Qt::UserRole).toByteArray());  //获取照片数据
        } else {
            updateQuery.addBindValue(item->text().trimmed());  //获取文本数据
        }
        updateQuery.addBindValue(id);  //绑定学号
        //执行更新
        if (!updateQuery.exec()) {
            throw std::runtime_error("Failed to update student information :" + updateQuery.lastError().text().toStdString());
        }
        //提交事务
        QSqlDatabase::database().commit();  //提交事务
    }
    catch(const std::exception& e)
    {
        //回滚事务
        QSqlDatabase::database().rollback();  //回滚事务
        //刷新表格
        refreshTable();
        QMessageBox::warning(this, tr("Error"), QString::fromUtf8(e.what()));
    }
}
